#include "StdAfx.h"
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include "errors.h"
#include "GemsecUtilities.h"

namespace Safe
{
	// Uses CryptEncodeObject to encode a structure.  Use EncodeFree to release data which is allocated.
	int CGemsecUtilities::Encode(const void * input, LPCSTR encodeType, CRYPT_DATA_BLOB &output)
	{
		if ((NULL == input) || (NULL == encodeType)) 
			return BAD_PARAM;

		output.pbData = NULL;
		output.cbData = 0;
		/// get the encoding length
		if( CryptEncodeObject(
				MY_ENCODING_TYPE, 
				encodeType, 
				input, 
				output.pbData, 
				&(output.cbData)) && 0 < output.cbData )
		{
			output.pbData = new BYTE[output.cbData];
			/// perform the actual encoding
			if( !CryptEncodeObject ( MY_ENCODING_TYPE, encodeType, input, output.pbData, &(output.cbData)) )
			{
				delete [] output.pbData;
				output.cbData = 0;
				output.pbData = NULL;
				return ENCODE_FAIL;
			}
		}
		else
		{
			return ENCODE_SIZE_FAIL;
		}
		return 0;
	}


	// Frees data allocated by Encode(), Decode(), CreateBlob()
	int CGemsecUtilities::FreeMem(CRYPT_DATA_BLOB * toFree)
	{
		if ((NULL == toFree)||(0 <= toFree->cbData)) return BAD_PARAM;
		if (NULL != toFree->pbData)	delete[] toFree->pbData;
		toFree->pbData = NULL;
		toFree->cbData = 0;
		return 0;
	}

	// Uses CryptDecodeObject to decode a structure.  
	// Use DecodeFree to release data allocated by this function
	int CGemsecUtilities::Decode(CRYPT_DATA_BLOB &input, LPCSTR lpDecodeType, CRYPT_DATA_BLOB &output)
	{
		if ((NULL == lpDecodeType) || (NULL == input.pbData) || (0 == input.cbData)) 
		{
			return BAD_PARAM;
		}

		output.pbData = NULL;
		output.cbData = 0;
		/// Get the decoding length
		if( CryptDecodeObject(
				MY_ENCODING_TYPE, 
				lpDecodeType, 
				input.pbData, 
				input.cbData,
				0, 
				output.pbData, 
				&(output.cbData)) )
		{
			if (0 == output.cbData) 
				return ENCODE_SIZE_FAIL;

			/// perform the actual decoding operation
			output.pbData = new BYTE[output.cbData];
			if( !CryptDecodeObject ( 
						MY_ENCODING_TYPE, 
						lpDecodeType, 
						input.pbData, 
						input.cbData,
						0, 
						output.pbData, 
						&(output.cbData)))
			{
				delete [] output.pbData;
				output.pbData = NULL;
				output.cbData = 0;
				return ENCODE_FAIL;
			}
		}
		return 0;
	}

	// creates the blob type needed by other functions
	// this function allocates memory in the blob parameter.  Use FreeMem to free the
	// object.
	int CGemsecUtilities::CreateBlob(const BYTE* pbInput, DWORD cbInput, CRYPT_DATA_BLOB &outBlob )
	{
		if ( (NULL == pbInput) || (0 >= cbInput) )
		{
			return BAD_PARAM;
		}

		outBlob.cbData = cbInput;
		outBlob.pbData = new BYTE[cbInput];
		memcpy_s( outBlob.pbData, outBlob.cbData, pbInput, cbInput);
		return 0;
	}

	// copies the binary part of a blob to a newly allocated void
	int CGemsecUtilities::Copy(CRYPT_DATA_BLOB &input, void ** output)
	{
		if ((NULL == output)) return BAD_PARAM;
		if ((NULL == input.pbData) || (0 == input.cbData)) return BAD_PARAM;
		(*output) = (void*) new BYTE[input.cbData];
		memcpy_s((*output), input.cbData, input.pbData, input.cbData);
		return 0;
	}

	// Frees memory allocated by Copy()
	void CGemsecUtilities::FreeVoid(void ** toFree)
	{
		if( toFree != NULL && *toFree != NULL ) 
		{
			delete[] (*toFree);
			*toFree = NULL;
		}
	}

	// returns TRUE if the two passed in BLOBs are equal
	BOOL CGemsecUtilities::BlobsAreEqual(CRYPT_DER_BLOB * first, CRYPT_DER_BLOB * second)
	{
		if ((NULL == first) || (NULL == second) || (NULL == first->pbData) || (NULL == second->pbData))
		{
			return FALSE;
		}
		if (first->cbData != second->cbData)
			return FALSE;

		return (0 == memcmp(first->pbData, second->pbData, first->cbData));
	}
}